/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package services;

import java.io.*;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.nio.ByteBuffer;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JOptionPane;
import javax.swing.JTable;
import javax.swing.table.DefaultTableModel;
import objects.UserInfo;

/**
 *
 * @author ntfsbk
 */
public class ShareManager {

    String userId;
    String serverIp;
    List<MyFile> myFiles;
    List<Object> lock;
    List<Integer> requestIndex;
    List<Float> receivedDataPerSecond;
    List<Float> receivedData;
    List<Float> sentDataPerSecond;
    List<RequestThread> requestThread;
    WelcomeThread welcomeThread;
    JTable table;
    Timer timer;
    DefaultTableModel model;
    XmlManager xmlmanager;
    int port;

    public ShareManager() {
    }

    public ShareManager(JTable table, List<MyFile> myFiles, XmlManager xmlmanager, int port,String userId,String serverIp) {

        this.userId=userId;
        this.serverIp=serverIp;
        this.myFiles = myFiles;
        lock = new ArrayList<Object>();

        requestIndex = new ArrayList<Integer>();
        receivedDataPerSecond = new ArrayList<Float>();
        receivedData = new ArrayList<Float>();
        sentDataPerSecond = new ArrayList<Float>();

        int length = myFiles.size();
        for (int i = 0; i < length; ++i) {
            requestIndex.add(new Integer(-1));
            receivedDataPerSecond.add(new Float(0));
            receivedData.add(new Float(0));
            sentDataPerSecond.add(new Float(0));
            lock.add(new Object());
        }

        requestThread = new ArrayList<RequestThread>();
        welcomeThread = new WelcomeThread();
        this.table = table;
        model = (DefaultTableModel) table.getModel();
        this.xmlmanager = xmlmanager;
        this.port = port;

        welcomeThread.start();
        timer = new Timer();
        timer.schedule(new updateTimer(), 1000, 1000);
    }

    public void AddDownloadFile(MyFile file, List<UserInfo> seedingUsers) {
        int length = myFiles.size();
        myFiles.add(file);
        DecimalFormat form = new DecimalFormat("0.00");
        float percent = (file.getCompleteData() / file.getFileSize()) * 100;
        model.addRow(new Object[]{
                    length + 1, file.getFileName(), Ultility.convertMem(file.getFileSize()),"0B/s", "0B/s", form.format(percent) + "%"
                });

        int indexTh = requestThread.size();
        RequestThread newDownloadThread = new RequestThread(length, seedingUsers);
        lock.add(new Object());

        requestIndex.add(new Integer(indexTh));
        receivedDataPerSecond.add(new Float(0));
        receivedData.add(new Float(0));
        sentDataPerSecond.add(new Float(0));
        requestThread.add(newDownloadThread);
        newDownloadThread.start();
    }

    public void AddSharedFile(MyFile file) {
        int length = myFiles.size();
        myFiles.add(file);
        model.addRow(new Object[]{
                    length + 1, file.getFileName(),Ultility.convertMem(file.getFileSize()), 0, 0, "100%"
                });
        lock.add(new Object());

        requestIndex.add(new Integer(-1));
        receivedDataPerSecond.add(new Float(0));
        receivedData.add(file.getFileSize());
        sentDataPerSecond.add(new Float(0));
    }

    class RequestThread extends Thread {

        int index;
        List<UserInfo> seedingUsers;
        boolean stop = false;

        public RequestThread() {
        }

        public RequestThread(int Index, List<UserInfo> seedingUsers) {
            index = Index;
            this.seedingUsers = seedingUsers;
        }

        public void setStop() {
            this.stop = true;
        }

        public boolean isStop() {
            return stop;
        }

        @Override
        public void run() {
            try {
                if (seedingUsers.size() > 0) {
                    String ip = seedingUsers.get(0).getUserAddress();
                    int port=seedingUsers.get(0).getPort();
                    InetAddress requestIP = InetAddress.getByName(ip);
                    Socket requestSocket = new Socket(requestIP, port);

                    DataOutputStream dataout = new DataOutputStream(requestSocket.getOutputStream());
                    DataInputStream datain = new DataInputStream(requestSocket.getInputStream());

                    int fileId = myFiles.get(index).getFileId();
                    dataout.writeInt(fileId);

                    int accept = datain.readInt();

                    if (accept == 2) {
                        String path = myFiles.get(index).getPathName();
                        File requestFile = new File(path);
                        BufferedOutputStream outToFile = new BufferedOutputStream(new FileOutputStream(requestFile));

                        byte[] receiveByte = new byte[8192];
                        int c;

                        try {
                            while ((c = datain.read(receiveByte)) != -1) {
                                outToFile.write(receiveByte);

                                float receive = receivedDataPerSecond.get(index).floatValue();
                                receive += c;
                                receivedDataPerSecond.set(index, receive);
                            }

                            //confirm download complete and start sharing
                            FileServices fs=new FileServices();
                            fs.confirmDownloadComplete(fileId,userId,serverIp);
                            
                            outToFile.close();
                            myFiles.get(index).setIsComplete(true);
                            myFiles.get(index).setCompleteData(myFiles.get(index).getFileSize());
                            model.setValueAt("100%", index, 5);
                        } catch (Exception e) {
                            e.printStackTrace();
                        }

                        JOptionPane.showMessageDialog(null, "complete", "title", JOptionPane.INFORMATION_MESSAGE);
                    }

                    requestSocket.close();
                    dataout.close();
                    datain.close();
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    class WelcomeThread extends Thread {

        ServerSocket welcomeSocket = null;

        @Override
        public void run() {
            try {
                ServerSocket welcomeSocket = new ServerSocket(port);
                while (true) {
                    new RespondThread(welcomeSocket.accept()).start();
                }

            } catch (Exception e) {
            }
        }

        @Override
        public void finalize() {
            try {
                try {
                    super.finalize();
                } catch (Throwable ex) {
                    Logger.getLogger(ShareManager.class.getName()).log(Level.SEVERE, null, ex);
                }
                welcomeSocket.close();
            } catch (Exception e) {
            }
        }
    }

    class RespondThread extends Thread {

        Socket clientSocket = null;
        int index;

        public RespondThread() {
        }

        public RespondThread(Socket ClientSocket, int Index) {
            this.clientSocket = ClientSocket;
            this.index = Index;
        }

        public RespondThread(Socket ClientSocket) {
            this.clientSocket = ClientSocket;
        }

        @Override
        public void run() {
            try {

                DataOutputStream dataout = new DataOutputStream(clientSocket.getOutputStream());
                DataInputStream datain = new DataInputStream(clientSocket.getInputStream());

                int fileId = datain.readInt();

                System.out.print(myFiles.size() - 1);
                System.out.println(fileId);
                int accept = 1;
                for (int i = 0; i < myFiles.size(); ++i) {
                    int fid = myFiles.get(i).getFileId();
                    boolean complete = myFiles.get(i).isComplete();
                    if (fid == fileId && complete == true) {
                        accept = 2;
                        index = i;
                        break;
                    }
                }

                ByteBuffer bb = ByteBuffer.allocate(4);
                bb.putInt(accept);
                byte[] respondByte = bb.array();

                dataout.write(respondByte);

                if (accept == 2) {
                    String nameFile = myFiles.get(index).getPathName();
                    File transferFile = new File(nameFile);
                    BufferedInputStream inFromfile = new BufferedInputStream(new FileInputStream(transferFile));

                    int c;
                    byte[] sendByte = new byte[8192];

                    while ((c = inFromfile.read(sendByte)) != -1) {
                        dataout.write(sendByte);
                        //synchronized(lock.get(index)){
                        float sent = sentDataPerSecond.get(index).floatValue();
                        sent += c;
                        sentDataPerSecond.set(index, sent);
                        //}
                    }
                    inFromfile.close();
                }

                dataout.close();
                datain.close();
                clientSocket.close();

            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    class updateTimer extends TimerTask {

        @Override
        public void run() {
            for (int i = 0; i < myFiles.size(); ++i) {
                if (!myFiles.get(i).isComplete()) {
                    float receive = receivedData.get(i) + receivedDataPerSecond.get(i);
                    receivedData.set(i, receive);
                    myFiles.get(i).setCompleteData(receive);
                    
                    xmlmanager.updateCompleteData(receive,myFiles.get(i).getFileId());
                    
                    float percent = (receivedData.get(i) / myFiles.get(i).getFileSize()) * 100;
                    DecimalFormat form = new DecimalFormat("0.00");
                    model.setValueAt(form.format(percent) + "%", i, 5);
                }

                model.setValueAt(Ultility.convertMem(receivedDataPerSecond.get(i).floatValue())+"/s", i, 3);
                model.setValueAt(Ultility.convertMem(sentDataPerSecond.get(i).floatValue())+"/s", i, 4);
                
                receivedDataPerSecond.set(i, new Float(0));
                sentDataPerSecond.set(i, new Float(0));
            }
        }
    }
}
